#ifndef SESSION_H
#define SESSION_H

namespace fx {

    FX_DECLARE_CLASS(Server);
    FX_DECLARE_CLASS(Buffer);
    FX_DECLARE_CLASS(HttpHeader);
    FX_DECLARE_CLASS(HttpRequestHeader);
    FX_DECLARE_CLASS(Session);

    class Session
        : public boost::noncopyable
        , public boost::enable_shared_from_this<Session>
    {
    public:
        static SessionPtr Create(ServerPtr server);

    public:
        tcp::socket& Socket() { return socket_; }
        bool IsRunning() const { return is_running_; }

        void Start();
        void Stop();
        std::string GetToken() const { return token_; }
        std::string GetLastPeerToken() const { return last_peer_token_; }

    public:
        void OnMessage(HttpHeaderPtr header, Buffer content);
        void OnMatching();
        void OnMatched(const std::string& peer_token);
        void OnDisconnect();
        void OnStatistic();

    protected:
        void AsyncReadHeader();
        void AsyncWriteResponse();
        void PrepareRequestHeadBufferHandler(const boost::system::error_code& error, std::size_t bytes_transferred);
        void PrepareRequestHeadBuffer();
        void RequestHeadHandler();
        void RequestContentHandler(HttpRequestHeaderPtr request, const boost::system::error_code& error, std::size_t bytes_transferred);
        void ProcessRequest(HttpRequestHeaderPtr request, Buffer content);
        void ResponseWriteHandler(const boost::system::error_code& error, std::size_t bytes_transferred);

    protected:
        Session(ServerPtr server);

        std::string token_;
        std::string last_peer_token_;

        boost::uint32_t request_head_state_;
        boost::asio::streambuf request_head_buf_;
        boost::asio::streambuf request_buf_;
        boost::asio::streambuf response_buf_;

        tcp::socket socket_;
        std::string head_delim_;
        bool is_running_;
        boost::uint32_t session_state_;

        ServerPtr server_;
    };

}

#endif//SESSION_H
